<?php
class init{
    private $host;   //服务器名
    private $port;  //端口号
    private $user;  //账号
    private $password;  //密码
    private $db_name;   //数据库名
    private $charset;   //字符集
    private $prefix;    //表前缀
    private $link;  //连接资源
    //定义参数错误
    protected $para_error = [];
    //表达式
    protected $exp = [];
    //表名(不含前缀)
    protected $name = '';
    //表名(含前缀)
    protected $table = '';
    //查询参数
    protected $options = [];


    /**
     * 构造函数
     * 自动获取数据库连接
     * init constructor.
     * @param array $arr
     */
    public function __construct($arr = array()){
        //信息初始化
        $this -> host = isset($arr['host']) ? $arr['host'] : '127.0.0.1';
        $this -> port = isset($arr['port']) ? $arr['port'] : '3306';
        $this -> user = isset($arr['user']) ? $arr['user'] : 'root';
        $this -> password = isset($arr['password']) ? $arr['password'] : 'root';
        $this -> db_name = isset($arr['db_name']) ? $arr['db_name'] : 'test';
        $this -> charset = isset($arr['charset']) ? $arr['charset'] : 'utf8';
        $this -> prefix = isset($arr['prefix']) ? $arr['prefix'] : '';

        //连接数据库
        $this -> connect();

        //设置字符集
        $this -> setCharset();

        //定义表达式
        $this->exp();

    }

    /**
     * 创建mysqli对象连接
     * @return $this
     */
    private function connect(){
        //mysqli扩展连接
        $this -> link = new MySQLi($this->host,$this->user,$this->password,$this->db_name,$this->port);
        //连接失败
        if(!$this->link){
            echo '数据库连接失败：<br>';
            echo '错误编码：' . $this->link->connect_errno . '<br>';
            echo '错误内容：' . $this->link->connect_error . '<br>';
        }
        return $this;
    }

    /**
     * 设置字符集
     * @return $this
     */
    private function setCharset(){
        $this->query("set names {$this->charset} ");
        return $this;
    }

    /**
     * 设置表达式
     * @return $this
     */
    public function exp(){
        $this->exp = array(
            "eq" => "=",
            "neq" => "<>",
            "gt" => ">",
            "egt" => ">=",
            "lt" => "<",
            "elt" => "<=",
            "notlike" => "NOT LIKE",
            "not like" => "NOT LIKE",
            "like" => "LIKE",
            "in" => "IN",
            "exp" => "EXP",
            "notin" => "NOT IN",
            "not in" => "NOT IN",
            "between" => "BETWEEN",
            "not between" => "NOT BETWEEN",
            "notbetween" => "NOT BETWEEN",
            "exists" => "EXISTS",
            "notexists" => "NOT EXISTS",
            "not exists" => "NOT EXISTS",
            "null" => "NULL",
            "notnull" => "NOT NULL",
            "not null" => "NOT NULL",
            "> time" => "> TIME",
            ">= time" => ">= TIME",
            "< time" => "< TIME",
            "<= time" => "<= TIME",
            "between time" => "BETWEEN TIME",
            "notbetween time" => "NOT BETWEEN TIME",
            "not between time" => "NOT BETWEEN TIME"
        );
        return $this;
    }

    /**
     * 设置表名不含表前缀
     * @param $name
     * @return $this
     */
    public function name($name){
        $this->name = $name;
        return $this;
    }

    /**
     * 设置表名含前缀
     * @param $table
     * @return $this
     */
    public function table($table){
        $this->table = $this->prefix.$table;
        return $this;
    }

    /**
     * 查询参数
     * @param array $options
     * @return $this
     */
    public function options(array $options){
        $this->options = $options;
        return $this;
    }

    /**
     * 查询字段
     * @param $field
     * @return $this
     */
    public function field($field){
        //判断是否为空，为空则直接返回
        if(empty($field)){
            return $this;
        }
        //获取数据类型
        $data_type = gettype($field);
        switch ($data_type){
            case 'boolean' :
                if($field){
                    $this->options['field'] = "true";
                }else{
                    $this->options['field'] = "false";
                }
                break;
            case 'integer' :
            case 'string' :
                //过滤特殊字符
                $field = $this->subChar(strval($field));
                $this->options['field'] = $field;
                break;
            case 'array' :
                foreach ($field as &$v){
                    if(gettype($v) == 'boolean'){
                        if($v){
                            $v = "true";
                        }else{
                            $v = "false";
                        }
                    }
                    $v = $this->subChar(strval($v));
                }
                $this->options['field'] = $field;
                break;
        }
        return $this;
    }


    public function where($field){
        $and = array();
        //遍历条件参数
        foreach ($field as $k => $v){
            //判断类型
            switch (gettype($v)){
                //布尔型，将其转换成字符串，并赋值
                case 'boolean' :
                    if($v){
                        $and[] = $k . "='true'";
                    }else{
                        $and[] = $k . "='false'";
                    }
                    break;
                //字符串，赋值并带有引号
                case 'string' :
                    $and[] = $k . "='" . $v ."'";
                    break;
                //整型，直接赋值
                case 'integer' :
                    $and[] = $k ."=". $v;
                    break;
                //数组，则查询是否有关键表达式，并进行赋值，若无，则提示传参错误
                case 'array' :
                    break;
            }
        }
        return $and;
//        print_r($field);
    }

    /**
     * @param $sql
     * @return mixed
     */
    public function query($sql){
        //发送SQL请求
        $rst = $this->link->query($sql);
        //判断结果
        if(!$rst){
            echo "执行出错：<br>";
            echo "错误编码：". $this->link->errno ."<br>";
            echo "错误内容：". $this->link->error ."<br>";
        }
        return $rst;
    }

    /**
     * 查询一条记录
     * @param $sql
     * @return array|null|string
     */
    public function find($sql){
        $rst = $this->query($sql);
        return mysqli_num_rows($rst) ? mysqli_fetch_assoc($rst) : "";
    }

    /**
     * 查询所有记录
     * @param $sql
     * @return array
     */
    public function select($sql){
        $rst = $this->query($sql);
        $arr = array();
        if(mysqli_num_rows($rst)){
            while ($row = mysqli_fetch_assoc($rst)){
                $arr[] = $row;
            }
        }
        return $arr;
    }

    public function closeCon(){
        return $this->link->close();
    }

    /**
     * 字符过滤
     * @param $char
     * @return null|string|string[]
     */
    public function subChar($char){
        $preg = '/[\<\'\"\(\>\)?!\|#{}]/';
        $data = $char;
        if(preg_match ($preg,$char)){
            //去掉包含如上的符号
            $data = preg_replace($preg,"",$char);
        }
        return $data;
    }

    public function inExp($arr){
        //数组维度判断
        if($this->array_depth($arr) != 1){
            $this->para_error[] = '传入参数不正确，请核对后进行操作。';
            return $this;
        }

    }

    /**
     * 判断数组维度
     * 返回数值，若为0则表示不是数组，1表示一维数组，以此类推
     * @param $array
     * @return int
     */
    private function array_depth($array) {
        //判断是否为数组，若不是返回0
        if(!is_array($array))  return 0;
        //初始化为一维数组
        $max_depth = 1;
        //遍历判断数组维度
        foreach ($array as $value) {
            if (is_array($value)) {
                $depth = $this->array_depth($value) + 1;
                if ($depth > $max_depth) {
                    $max_depth = $depth;
                }
            }
        }
        return $max_depth;
    }
}